<?php
namespace App\Services\Product;

use App\Events\DeviceInfoUpdate;
use App\Events\UserCommand;
use App\Exceptions\DeviceException;
use App\Facades\UserManager;
use App\Facades\DeviceManager;
use App\Facades\WeChatService;
use App\Jobs\SendTemplateMessage;
use App\Models\Device as DeviceModel;
use App\Utils\Device;
use Cache;
use Carbon\Carbon;
use DB;
use Exception;
use Illuminate\Foundation\Bus\DispatchesJobs;

class DeviceService
{
	use DispatchesJobs;

	/**
	 * 绑定
	 * @param  string $deviceCode 设备编码
	 */
	public function bind($deviceCode)
	{

		DB::transaction(function() use ($deviceCode) {
		    $wxUser = UserManager::getWxUser();
		    UserManager::updateCurrentDevice($wxUser, $deviceCode);
		    DeviceManager::add($wxUser, $deviceCode);
		    Cache::forget($wxUser->open_id);
		});
	    if(!Cache::has($deviceCode.'fd'))
	    {
	    	throw new DeviceException('notConnect');
	    }
	}

	/**
	 * 根据设备号解绑设备
	 * @param  string $deviceCode 设备编码
	 */
	public function unbindByDeviceCode($deviceCode = null)
	{
		try{
			return DB::transaction(function() use ($deviceCode) {
				$user = UserManager::getWxUser();
				if(is_null($deviceCode))
				{
					$deviceCode = $user->current_device_code;
				}
				UserManager::updateAll($deviceCode, null);
				DeviceManager::deleteByUserDeviceCode($user, $deviceCode);
				Cache::forget($user->open_id);

				if($user->current_device_code == $deviceCode){
					return $this->getNewCurrentDeviceCode($user);
				}
			});
		}catch(Exception $e){
			throw new DeviceException('unbind');
		}
	}

	/**
	 * 获取新的当前设备码
	 * @param   $user 
	 * @return        
	 */
	public function getNewCurrentDeviceCode($user)
	{
		return DB::transaction(function() use ($user) {
			$devices = DeviceManager::getDeviceListByUser($user, false);
			if(count($devices))
			{
				$newDeviceCode = $devices->first()['code'];
				UserManager::updateCurrentDevice($user, $newDeviceCode);
				return $newDeviceCode;
			}
		});
	}

	/**
	 * 获取设备状态
	 * @return array 	设备状态
	 */
	public function getState($throwException = true)
	{
		$wxUser = UserManager::getWxUser();
		$deviceCode = $wxUser->current_device_code;
		if(is_null($deviceCode))
		{
			$devices = DeviceManager::getDeviceListByUser($wxUser);
			if(count($devices))
			{
				$deviceCode = $devices[0]['code'];
				UserManager::updateCurrentDevice($wxUser, $deviceCode);
				Cache::forget($wxUser->open_id);
			}
			else
			{
				throw new DeviceException('noBind');
			}
		}
		DeviceManager::isBound($wxUser, $deviceCode);
		$state = Cache::get($deviceCode.'state');
		if(count($state) && Cache::has($deviceCode.'fd'))
		{
			return $state;
		}
		if($throwException){
			throw new DeviceException('notConnect');
		}
		
	}

	/**
	 * 获取绑定设备列表
	 * @return array 	设备号数组       
	 */
	public function getDeviceInfoListByUser($user = null, $throwException = true)
	{
		if(is_null($user))
		{
			$user = UserManager::getWxUser();
		}
		$devices = DeviceManager::getDeviceListByUser($user);
		if(!count($devices) && $throwException)
		{
			throw new DeviceException('noBind');
		}

		$deviceList = [];
		for($i = 0, $j = count($devices); $i < $j; $i++)
		{
			if($devices[$i]->code == $user->current_device_code)
			{
				$deviceList[$i]['current'] = 1;
			}
			else
			{
				$deviceList[$i]['current'] = 0;
			}
			$deviceList[$i]['device_code'] = $devices[$i]->code;
		}
		return $deviceList;
		
	}

	/**
	 * 切换当前控制设备
	 * @param  string $deviceCode 设备编码
	 */
	public function change($deviceCode)
	{
		$wxUser = UserManager::getWxUser();
		DeviceManager::isBound($wxUser, $deviceCode);
		UserManager::updateCurrentDevice($wxUser, $deviceCode);
		Cache::forget($wxUser->open_id);
		if(!Cache::has("$deviceCode".'fd'))
	    {
	    	throw new DeviceException('notConnect');
	    }
	}

	/**
	 * 发送控制命令
	 * @param  string $command 命令
	 */
	public function control($command, $num)
	{
		$openId = session('openId');
		$user = Cache::remember($openId, 60, function(){
			return UserManager::getWxUser();
		});
		$state = Cache::get(($user->current_device_code).'state');
		if($state['decStatus'] == 7 && $command != 'power_on')
		{
			throw new DeviceException('powerOff');
		}
		event(new UserCommand($command, $num));
	}

	public function getCmd($command, $num)
	{
		$openId = session('openId');
		$user = Cache::remember($openId, 60, function(){
			return UserManager::getWxUser();
		});
		$state = Cache::get(($user->current_device_code).'state');
		
		$binDeviceCode = Cache::get(($user->current_device_code.'BinDeviceCode'));

		switch ($command)
		{
			case 'power_on':
				$cmd = Device::getCmdByte(1, 1, 0, $binDeviceCode);
				break;
			case 'power_off':
				$cmd = Device::getCmdByte(1, 0, 0, $binDeviceCode);
				break;
			case 'unlock':
				$cmd = Device::getCmdByte(17, 1, 0, $binDeviceCode);
				break;
			case 'wash':
				if($state['decStatus'] == 5)
				{
					return false;
				}
				$cmd = Device::getCmdByte(3, 1, 0, $binDeviceCode);
				break;
			case 'wash_cancel':
				$cmd = Device::getCmdByte(3, 0, 0, $binDeviceCode);
				break;
			case 'reset_filter':
				$cmd = Device::getCmdByte(4, 0, $num, $binDeviceCode);
				break;
			case 'set_water_temperature':
				$cmd = Device::getCmdByte(14, substr($num, 0, strlen($num) - 2), 0, $binDeviceCode);
				break;
			default:
				throw new DeviceException('command');

		}
		return $cmd;
	}

	/**
	 * 发送模板消息
	 * @param   $user 
	 * @param   $data 
	 * @return        
	 */
	public function sendTemplateMessage($user = null, $data = null)
	{
		$remindTimesArray = str_split($user->pivot->remind_times);
		$sendData = [
		    'touser' => $user->open_id,
		    'template_id' => env('TEMPLATE_ID'),
		    'url' => "http://www.konka.com/index.php",
		    'data' => [
		        'first' => ['value' => '尊敬的用户，您好！您的智能净水器滤芯即将到期'],
		        'keyword1'  => ['value' => '智能净水器'],
		        'remark'    => ['value' => '您的智能净水器滤芯将达到最大使用期限，请及时更换！']
		    ]
		];

		for($i = 0; $i < 2; $i++)
		{
		    if(($remindTimesArray[$i] == 0 && $data['filter'.($i+1)] == 5) || ($remindTimesArray[$i] == 1 && $data['filter'.($i+1)] == 0))
		    {
		    	$filterName = ($i == 0) ? '滤芯' : 'RO反渗透膜';
	            $sendData['data']['keyword2']['value'] = $filterName.'使用寿命剩余'.$data['filter'.($i+1)].'%';
	            WeChatService::sendTemplateMessage($sendData);
	            if($i == 0)
	            {
	            	$firstUpdateData = $remindTimesArray[0] + 1;
	            }
	            else
	            {
	            	$secondUpdateData = $remindTimesArray[1] + 1;
	            }
	        }
		}

		$firstUpdateData = isset($firstUpdateData) ? $firstUpdateData : $remindTimesArray[0];
		$secondUpdateData = isset($secondUpdateData) ? $secondUpdateData : $remindTimesArray[1];
		$updateData = ['remind_times' => $firstUpdateData.$secondUpdateData];
		DeviceManager::updateWxDevice($user->pivot->user_id, $user->pivot->device_id, $updateData);
	}

	/**
	 * 获取设备列表
	 * @param   $deviceCode 
	 * @param   $status     
	 * @return              
	 */
	public function getDeviceRecordLlist($deviceCode, $status)
	{
		$resultSet = DeviceManager::getAllDeviceInfoWithCodeByStatus($status, $deviceCode);
		return $resultSet->latest()->paginate(8);
	}

	/**
	 * 根据设备码获取设备信息
	 * @param   $deviceCode 
	 * @return              
	 */
	public function getDeviceInfoListByDeviceCode($deviceId)
	{
		$deviceInfos = DeviceManager::getAllDeviceInfoWithCodeByDeviceCode($deviceId)
			->with(['device' => function($query){
				$query->with(['wxUsers' => function($query){
					$query->select(['wx_users.user_id', 'open_id']);
				}])->select(['id', 'code']);
		}])
		->paginate(10);
		return $deviceInfos;
	}

	public function getHreatBeatData(){
		return pack("v5C3V2v", 0x00bb, 0x0006, 0x0000, 0x000D, 0x0002, 0x12, 0x00, 0x00, 0X00000000, 0X00000000, 0x4FE5);
	}

	/**
	 * 处理设备数据
	 * @return  
	 */
	public function handle($dataCmd, $fd, $data)
	{
		if ($dataCmd == 0x0001) {
		    $formatData = Device::dataFormat($data);
		    // logger($formatData);
		    
		    if($formatData['decStatus'] != 0)
		    {
			    event(new DeviceInfoUpdate($formatData));
			    
			    DeviceManager::isCreateDeviceRecord($formatData['deviceCode']);
			    
			    //缓存设备数据
			    $this->cacheDeviceData($formatData, $fd, $data);
			    
			    $this->sendInformMessage($formatData);
			    
			    $this->isSaveDeviceData($formatData);
		    }
        }
	}

	/**
	 * 缓存设备相关信息
	 * @param   $formatData 
	 * @param   $fd         
	 * @param   $data       
	 * @return              
	 */
	public function cacheDeviceData($formatData, $fd, $data)
	{
		$expiresAt = Carbon::now()->addMinutes(env('CACHE_DEVICE_DATA'));
		
		//缓存设备连接 fd
		Cache::put($formatData['deviceCode'].'fd', $fd, $expiresAt);
		//缓存设备数据
		Cache::put($formatData['deviceCode'].'state', $formatData, $expiresAt);

		//缓存设备码二进制数据
		Cache::put($formatData['deviceCode'].'BinDeviceCode', substr($data, strlen($data) - 10, 8), $expiresAt);
	}

	/**
	 * 发送模板消息
	 * @param   $formatData 
	 * @return              
	 */
	public function sendInformMessage($formatData)
	{
		if($formatData['filter1'] <= DeviceModel::REMIND_LIMIT || $formatData['filter2'] <= DeviceModel::REMIND_LIMIT)
		{
			$this->dispatch(new SendTemplateMessage($formatData));
		}
	}

	/**
	 * 存储记录
	 * @param   $formatData 
	 * @return              
	 */
	public function isSaveDeviceData($formatData)
	{
		if(!Cache::has($formatData['deviceCode'].'record'))
		{
			$this->saveDeviceData($formatData);
			Cache::put($formatData['deviceCode'].'record', 1, Carbon::now()->addMinutes(60*24));
		}
		if($formatData['decStatus'] == 4 && !Cache::has($formatData['deviceCode'].'recordHydropenid'))
		{
			$this->saveDeviceData($formatData);
			Cache::put($formatData['deviceCode'].'recordHydropenid', 1, Carbon::now()->addMinutes(60*24));
		}
		if($formatData['decStatus'] == 2 && !Cache::has($formatData['deviceCode'].'recordOverhaul'))
		{
			$this->saveDeviceData($formatData);
			Cache::put($formatData['deviceCode'].'recordOverhaul', 1, Carbon::now()->addMinutes(60*24));
		}
	}

	public function saveDeviceData($formatData)
	{
		$createData = [
			'device_code' => $formatData['deviceCode'],
			'TDS1' => $formatData['TDS1'],
			'TDS2' => $formatData['TDS2'],
			'dec_status' => $formatData['decStatus'],
			'effluent_status' => $formatData['effluentStatus'],
			'water_temperature' => $formatData['waterTemperature'],
			'filter_cnt1' => $formatData['filterCnt1'],
			'filter_cnt2' => $formatData['filterCnt2'],
			'filter_set1' => $formatData['filterSet1'],
			'filter_set2' => $formatData['filterSet2'],
			'water_cnt' => $formatData['waterCnt'],
			'water_time' => $formatData['waterTime'],
		];
		DeviceManager::save($createData);
	}

	public function sendHeartBeatData($fd)
	{
		event(new UserCommand('heart_beat_data', null, $fd));
	}

	public function isBindAnyDevice()
	{
		$wxUser = UserManager::getWxUser();
		$deviceCode = $wxUser->current_device_code;
		if(is_null($deviceCode))
		{
			$devices = DeviceManager::getDeviceListByUser($wxUser);
			if(count($devices))
			{
				$deviceCode = $devices[0]['code'];
				UserManager::updateCurrentDevice($wxUser, $deviceCode);
				Cache::forget($wxUser->open_id);
			}
			else
			{
				throw new DeviceException('noBind');
			}
		}
	}

}